﻿using System;
using System.IO;
using up7.db.biz;
using up7.db.sql.model;
using up7.db.utils;

namespace up7.db.model
{
    public enum StorageType
    {
        /// <summary>
        /// io存储，文件保存在服务器中
        /// </summary>
        IO, 
        FastDFS, 
        Minio, 
        /// <summary>
        /// 阿里云对象存储
        /// </summary>
        OSS,
        OBS
    }

    public class FileInf
    {
        [DataBase("f_id")]
        public string id = string.Empty;
        
        [DataBase("f_pid")]
        public string pid = string.Empty;
        
        [DataBase("f_pidRoot")]
        public string pidRoot = string.Empty;
        
        [DataBase("f_fdTask")]
        public bool fdTask = false;//是否是一个文件夹

        /// <summary>
        /// 是否是文件夹中的子文件
        /// </summary>
        [DataBase("f_fdChild")]
        public bool fdChild = false;

        /// <summary>
        /// 用户ID。与第三方系统整合使用。
        /// </summary>	
        [DataBase("f_uid")]
        public string uid = string.Empty;

        public string blockMd5=string.Empty;

        /// <summary>
        /// 块压缩
        /// </summary>
        public bool blockCompress = false;
        public string blockCompressType = "gzip";

        /// <summary>
        /// 块偏移，基于整个文件
        /// </summary>
        [DataBase("f_blockOffset")]
        public long blockOffset = 0;//块偏移

        /// <summary>
        /// 块索引，基于1
        /// </summary>
        [DataBase("f_blockIndex")]
        public int blockIndex = 0;//块索引

        /// <summary>
        /// 块总数
        /// </summary>
        [DataBase("f_blockCount")]
        public int blockCount = 0;

        /// <summary>
        /// 块大小
        /// </summary>
        [DataBase("f_blockSize")]
        public int blockSize = 0;//块大小

        /// <summary>
        /// 块加密标识
        /// </summary>
        public bool blockEncrypt = false;

        /// <summary>
        /// 块加密大小
        /// </summary>
        public int blockSizeCry = 0;
        /// <summary>
        /// 块压缩大小
        /// </summary>
        public int blockSizeCpr = 0;

        /// <summary>
        /// 用于第三方存储的对象ID，如FastDFS,Minio等
        /// </summary>
        public String object_id = "";

        /// <summary>
        /// 加密存储
        /// </summary>
        [DataBase("f_encrypt")]
        public bool encrypt = false;

        /// <summary>
        /// 加密算法类型,aes,sm4
        /// </summary>
        [DataBase("f_encryptAlgo")]
        public string encryptAlgorithm = "aes";

        public int fileCount = 0;

        /// <summary>
        /// 文件在本地电脑中的名称。
        /// </summary>
        [DataBase("f_nameLoc")]
        public string nameLoc = string.Empty;
        
        /// <summary>
        /// 文件在服务器中的名称。
        /// </summary>
        [DataBase("f_nameSvr")]
        public string nameSvr = string.Empty;
        
        /// <summary>
        /// 文件在本地电脑中的完整路径。示例：D:\Soft\QQ2012.exe
        /// </summary>
        [DataBase("f_pathLoc")]
        public string pathLoc = string.Empty;
        
        /// <summary>
        /// 文件在服务器中的完整路径。示例：F:\ftp\uer\md5.exe
        /// </summary>
        [DataBase("f_pathSvr")]
        public string pathSvr = string.Empty;
        /// <summary>
        /// 文件块根目录
        /// f:/webapps/files/年/月/日/guid/file-guid/
        /// </summary>
        public string blockPath = string.Empty;
        
        /// <summary>
        /// 本地路径：D:/soft/safe/360.exe
        /// 相对路径 soft/safe/360.exe
        /// 文件在服务器中的相对路径。
        /// </summary>
        [DataBase("f_pathRel")]
        public string pathRel = string.Empty;
        
        /// <summary>
        /// 文件MD5
        /// </summary>
        [DataBase("f_md5")]
        public string md5 = string.Empty;
        
        /// <summary>
        /// 数字化的文件长度。以字节为单位，示例：120125
        /// 文件大小可能超过2G，所以使用long
        /// </summary>
        [DataBase("f_lenLoc")]
        public long lenLoc = 0;

        /// <summary>
        /// 本地文件加密后的大小
        /// </summary>
        [DataBase("f_lenLocSec")]
        public long lenLocSec = 0;

        /// <summary>
        /// 格式化的文件尺寸。示例：10.03MB
        /// </summary>
        [DataBase("f_sizeLoc")]
        public string sizeLoc = "0byte";

        public string sizeSvr = "0byte";
        
        /// <summary>
        /// 已上传大小。以字节为单位
        /// 文件大小可能超过2G，所以使用long
        /// </summary>
        [DataBase("f_lenSvr")]
        public long lenSvr = 0;

        /// <summary>
        /// 已上传百分比。示例：10%
        /// </summary>
        [DataBase("f_perSvr")]
        public string perSvr = "0%";

        /// <summary>
        /// PostComplete
        /// </summary>
        [DataBase("f_complete")]
        public bool complete = false;

        /// <summary>
        /// PostedTime
        /// </summary>
        [DataBase("f_time")]
        public DateTime time = DateTime.Now;

        /// <summary>
        /// IsDeleted
        /// </summary>
        [DataBase("f_deleted")]
        public bool deleted = false;

        /// <summary>
        /// 是否已经扫描完毕，提供给大型文件夹使用
        /// 大型文件夹上传完毕后开始扫描
        /// </summary>
        [DataBase("f_scan")]
        public bool scaned = false;

        /// <summary>
        /// 存储类型：io,oss,obs,cos,aws
        /// </summary>
        [DataBase("f_storage")]
        public string storage = "io";

        public StorageType storageType = StorageType.IO;

        /// <summary>
        /// 对象存储key
        /// </summary>
        [DataBase("f_object_key")]
        public string objectKey = string.Empty;

        /// <summary>
        /// 对象存储key.url
        /// </summary>
        [DataBase("f_object_url")]
        public string objectUrl = string.Empty;

        /// <summary>
        /// 计算文件加密后的大小，16字节对齐
        /// </summary>
        public void calLenLocSec()
        {
            long a = this.lenLoc % 16;
            this.lenLocSec = this.lenLoc + (16 - (a > 0 ? a : 16));
            
            if (this.encryptAlgorithm.Equals("sm4"))
            {
                this.calLenLocSecSm4();
            }
        }

        /// <summary>
        /// sm4-cbc-pkcs5padding
        /// (块大小* 块对齐大小) + 最后一块对齐大小
        /// </summary>
        public void calLenLocSecSm4()
        {
            //每一块对齐大小
            this.blockSizeCry = UtilsTool.sm4AlignBlockSize(this.blockSize);

            //块总数-1 * 块对齐大小
            this.lenLocSec = (this.blockCount-1) * this.blockSizeCry;

            //最后一块对齐大小
            long lastSize = this.lenLoc % this.blockSize;
            lastSize = UtilsTool.sm4AlignBlockSize((int)lastSize);

            this.lenLocSec += lastSize;
        }

        public string parentDir()
        {
            return PathTool.parentDir(this.pathSvr);
        }

        public void saveScheme()
        {
            FolderSchema fs = new FolderSchema();
            this.calLenLocSec();//自动计算文件加密后的大小
            fs.addFile(this);
        }

        public string schemaFile()
        {
            return Path.Combine(this.parentDir(), "schema.txt");
        }
        public string formatSize(long byteCount)
        {
            string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
            if (byteCount == 0)
                return "0" + suf[0];
            long bytes = Math.Abs(byteCount);
            int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
            double num = Math.Round(bytes / Math.Pow(1024, place), 1);
            return (Math.Sign(byteCount) * num).ToString() + suf[place];
        }
    }
}
